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.
This commit is contained in:
OlgunR
2026-06-19 14:38:12 +02:00
parent b88f011701
commit 64be11f7ad
3 changed files with 151 additions and 7 deletions

View File

@@ -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.1 - ProcessDocument Ordner gelöscht (Application Layer cleanup)
- ? Step 3.2.2 - Test-Ordnerstruktur erstellt (Unit/Infrastructure/Services/PdfProcessing) - ? 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.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 ### ?? In Progress
- **Phase 3, Step 3.2:** DevExpressPdfProcessor (TDD) - **Phase 3, Step 3.2:** DevExpressPdfProcessor (TDD)
- **NEXT:** Step 3.2.4 - DevExpressPdfProcessorTests.cs erstellen (TDD Red Phase) - **NEXT:** Step 3.2.5 - DevExpressPdfProcessor.cs implementieren (TDD Green Phase)
- **Progress:** 3/7 Mini-Steps abgeschlossen - **Progress:** 4/7 Mini-Steps abgeschlossen
### ? Pending ### ? Pending
- **Phase 3:** Infrastructure Layer - **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 | 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.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.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) |
--- ---

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
@@ -39,8 +39,4 @@
<ProjectReference Include="..\DocumentOperator.Infrastructure\DocumentOperator.Infrastructure.csproj" /> <ProjectReference Include="..\DocumentOperator.Infrastructure\DocumentOperator.Infrastructure.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Unit\Infrastructure\Services\PdfProcessing\" />
</ItemGroup>
</Project> </Project>

View File

@@ -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;
/// <summary>
/// Unit tests for DevExpressPdfProcessor.
/// Tests PDF validation and metadata extraction.
/// </summary>
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
/// <summary>
/// Loads a test PDF from embedded resources.
/// </summary>
/// <param name="filename">Name of the PDF file (e.g., "valid.pdf")</param>
/// <returns>PDF content as byte array</returns>
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<Task> act = async () => await _sut.ValidateAsync(pdfBytes!);
// Assert
await act.Should().ThrowAsync<PdfProcessingException>()
.WithMessage("*null*", "null input should be rejected");
}
[Fact]
public async Task ValidateAsync_EmptyBytes_ThrowsPdfProcessingException()
{
// Arrange
byte[] pdfBytes = Array.Empty<byte>();
// Act
Func<Task> act = async () => await _sut.ValidateAsync(pdfBytes);
// Assert
await act.Should().ThrowAsync<PdfProcessingException>()
.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<Task> act = async () => await _sut.ValidateAsync(pdfBytes);
// Assert
await act.Should().ThrowAsync<PdfProcessingException>()
.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
}